#include "speedup.h"
#include <cmath>

float diff_degree;
void smooth_all(int G, int no_cate, int * targets, int length, int width, int height)
{
    int unit=1<<G;
    for(int z=0; z<height; z+=unit){
        for(int y=0; y<width; y+=unit){
            for(int x=0;x<length;x+=unit){
                if (targets[x+y*width+width*length*z]>=0) continue;
                int cumm[no_cate];
                memset(cumm,0,no_cate*sizeof(int));
                for(int posz=z-unit;posz<=z+unit;posz+=unit){
                    if ((posz<0) || (posz>=height)) continue;
                    for(int posx=x-unit;posx<=x+unit;posx+=unit){
                        if ((posx<0) || (posx>=length)) continue;
                        for(int posy=y-unit;posy<=y+unit;posy+=unit){
                            if ((posy<0) || (posy>=width)) continue;
                            int value = targets[posx+posy*width+posz*length*width];
                            if ((value!=-1) && (value!=9)){
                                cumm[value]+=1;
                            }
                        }
                    }
                }
                int max=-1;
                int maxi=0;
                for(int i=0;i<no_cate;i++){
                    if (cumm[i]>max){
                        max=cumm[i];
                        maxi=i;
                    }
                }
                if (max<=0) continue;
                targets[x+y*length+z*length*width]=maxi;
            }
        }
    }
}
void find_border(int startid, int G, vector <coord> &sample, vector <int> &ids, int * targets, int length, int width, int height)
{
    set <int> candidate;
    candidate.clear();
    int diff=1;
    int unit=1<<G;
    int endid=sample.size();
    int objsize=unit;
    // For each point in the new samples
    if (G>1){
        for(int z=0;z<height;z+=objsize){
            for(int y=0;y<width;y+=objsize){
                for(int x=0;x<length;x+=objsize){
                    //3.1 Find nearest neibhors
                    for (int zshift=-1*unit;zshift<=unit;zshift+=unit){
                        diff=0;
                        int zpos=z+zshift;
                        if ((zpos<0)||(zpos>=height)) continue;
                        for (int xshift=-1*unit;xshift<=unit;xshift+=unit){
                            int xpos=x+xshift;
                            if ((xpos<0)||(xpos>=length)) continue;
                            for (int yshift=-1*unit;yshift<=unit;yshift+=unit){
                                int ypos=y+yshift;
                                if ((ypos<0)||(ypos>=width)) continue;
                                //3.2 calculating the maximum difference between these four neighbors
                                if (targets[x+length*y+length*width*z]!=targets[xpos+length*ypos+length*width*zpos]){
                                    diff=1;
                                }
                                if (diff==1) break;
                            }
                            if (diff==1) break;
                        }
                        if (diff==1) break;
                    }
                    for (int zshift=-1*unit;zshift<=unit;zshift+=unit){
                        int zpos=z+zshift;
                        if ((zpos<0)||(zpos>=height)) continue;
                        for (int xshift=-1*unit;xshift<=unit;xshift+=unit){
                            int xpos=x+xshift;
                            if ((xpos<0)||(xpos>=length)) continue;
                            for (int yshift=-1*unit;yshift<=unit;yshift+=unit){
                                if((xshift==0) && (yshift==0) && (zshift==0)) continue;
                                int ypos=y+yshift;
                                if ((ypos<0)||(ypos>=width)) continue;
                                if (diff==1){
                                    int nfid=xpos-xshift/2+length*(ypos-yshift/2)+length*width*(zpos-zshift/2);
                                    targets[nfid]=9;
                                    candidate.insert(nfid);
                                }else{
                                    targets[xpos-xshift/2+length*(ypos-yshift/2)+length*width*(zpos-zshift/2)]=targets[x+length*y+length*width*z];
                                }
                            }
                        }
                    }
                }
            }
        }
    }else{
        for(int z=0;z<height;z+=objsize){
            for(int y=0;y<width;y+=objsize){
                for(int x=0;x<length;x+=objsize){
                    //3.1 Find nearest neibhors
                    for (int zshift=-1*unit;zshift<=unit;zshift+=unit){
                        diff=0;
                        int zpos=z+zshift;
                        if ((zpos<0)||(zpos>=height)) continue;
                        for (int xshift=-1*unit;xshift<=unit;xshift+=unit){
                            int xpos=x+xshift;
                            if ((xpos<0)||(xpos>=length)) continue;
                            for (int yshift=-1*unit;yshift<=unit;yshift+=unit){
                                int ypos=y+yshift;
                                if ((ypos<0)||(ypos>=width)) continue;
                                //3.2 calculating the maximum difference between these four neighbors
                                int nfid=xpos-xshift/2+length*(ypos-yshift/2)+length*width*(zpos-zshift/2);
                                if (targets[x+length*y+length*width*z]!=targets[xpos+length*ypos+length*width*zpos]){
                                    targets[nfid]=9;
                                    candidate.insert(nfid);
                                }else{
                                    if(9==targets[nfid]) continue;
                                    targets[nfid]=targets[x+length*y+length*width*z];
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    int lowlevelunit=1<<(G-1);
    if ((height>lowlevelunit)&&(height%(lowlevelunit*2)==0)){
        for(int x=0;x<length;x+=lowlevelunit){
            for(int y=0;y<width;y+=lowlevelunit){
                if(G==1){
                    int nfid=x+length*((width/lowlevelunit-1)*lowlevelunit)+length*width*y;
                    targets[nfid]=9;
                    candidate.insert(nfid);
                }
                else{
                    int nfid=x+length*((width/lowlevelunit-1)*lowlevelunit)+length*width*y;
                    targets[nfid]=9;
                    candidate.insert(nfid);
                } 
            }
        }
    }
    if ((width>lowlevelunit)&&(width%(lowlevelunit*2)==0)){
        for(int x=0;x<length;x+=lowlevelunit){
            for(int z=0;z<height;z+=lowlevelunit){
                if(G==1){
                    int nfid=x+length*((width/lowlevelunit-1)*lowlevelunit)+length*width*z;
                    targets[nfid]=9;
                    candidate.insert(nfid);
                }
                else{
                    int nfid=x+length*((width/lowlevelunit-1)*lowlevelunit)+length*width*z;
                    targets[nfid]=9;
                    candidate.insert(nfid);
                } 
            }
        }
    }
    if ((length>lowlevelunit)&&(length%(lowlevelunit*2)==0)){
        for(int y=0;y<length;y+=lowlevelunit){
            for(int z=0;z<height;z+=lowlevelunit){
                if (G==1) {
                    int nfid=(length/lowlevelunit-1)*lowlevelunit+length*y+length*width*z;
                    targets[nfid]=9;
                    candidate.insert(nfid);
                }
                else {
                    int nfid=(length/lowlevelunit-1)*lowlevelunit+length*y+length*width*z;
                    targets[nfid]=9;
                    candidate.insert(nfid);
                }
            }
        }
    }
    for(set <int>::iterator it=candidate.begin();it!=candidate.end();it++){
        coord s;
        int fid=*it;
        s.x=fid%length;
        s.y=fid%(length*width)/length;
        s.z=fid/(length*width);
        sample.push_back(s);
    }
}
